package org.sunspotworld;

import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Observable;
import javax.swing.Timer;

/**
 *
 * @author Dustin
 * @version 1.0
 */

public class Model extends Observable implements Protocol {

    private ArrayList sunspots = new ArrayList();
    private long playTime;
    private long currentPlayTime;
    private Timer timer;

    /**
     * Query this model if it contains a SunSPOT with the given address.
     * @param address the addres of the wanted SunSPOT
     * @return boolean If this model contains this SunSPOT or not
     */
    public boolean contains(long address) {
        boolean contains = false;
        for (int i = 0; i < sunspots.size() && !contains; i++) {
            if (((SunSPOT) sunspots.get(i)).getAddress() == address) {
                contains = true;
            }
        }
        return contains;
    }

    public ArrayList getSunSPOTs() {
        return sunspots;
    }

    /**
     * Command to sort all SunSPOTs according to there address
     */
    private void selectionSort() {
        for (int i = 0; i < sunspots.size() - 1; i++) {
            int min = i;
            for (int j = i + 1; j < sunspots.size(); j++) {
                if (((SunSPOT)sunspots.get(j)).getAddress() <
                        ((SunSPOT)sunspots.get(min)).getAddress()) {
                    min = j;
                }
            }
            if (i != min) {
                SunSPOT temp = ((SunSPOT)sunspots.get(i));
                sunspots.set(i, ((SunSPOT) sunspots.get(min)));
                sunspots.set(min, temp);
            }
        }
    }

    public void addSunSPOT(long address, int score) {
        SunSPOT sunSPOT = new SunSPOT(address, score);
        sunSPOT.setLogging(System.currentTimeMillis());
        sunspots.add(sunSPOT);
        selectionSort();
        setChanged();
        notifyObservers();
    }

    /**
     * Command to update the score of a given SunSPOT by address.
     * @param address The SunSPOT to change score
     * @param score The new score
     */
    public void updateScore(long address, int score) {
        boolean updated = false;
        for (int i = 0; i < sunspots.size() && !updated; i++) {
            SunSPOT sunSPOT = ((SunSPOT) sunspots.get(i));
            if (sunSPOT.getAddress() == address) {
                sunSPOT.setLogging(System.currentTimeMillis());
                if(score != sunSPOT.getScore()) {
                    sunSPOT.setScore(score);
                    updated = true;
                    setChanged();
                    notifyObservers();
                }
            }
        }
    }

    /**
     * Command to update the state of a given SunSPOT by address.
     * @param address The SunSPOT to change state
     * @param state The new state
     */
    public void updateState(long address, int state) {
        boolean updated = false;
        for (int i = 0; i < sunspots.size() && !updated; i++) {
            SunSPOT sunSPOT = ((SunSPOT) sunspots.get(i));
            if (sunSPOT.getAddress() == address) {
                sunSPOT.setLogging(System.currentTimeMillis());
                if(state != sunSPOT.getState()) {
                    sunSPOT.setState(state);
                    updated = true;
                    setChanged();
                    notifyObservers();
                }
            }
        }
    }

    public long getCurrentPlayTime() {
        return currentPlayTime / 1000;
    }

    public long getPlayTime() {
        return playTime;
    }

    /**
     * Command to set the play time.
     * @param aPlayTime the amaint of time that will be played, given n seconds
     * @param aListener The ActionListener that will listen to the Timer.
     */
    public void setPlayTime(long aPlayTime, ActionListener aListener) {
        if(aPlayTime > 0) {
            playTime = aPlayTime;
            currentPlayTime = playTime;
            timer = new Timer(1000, aListener);
            timer.setActionCommand("TIMER");
            timer.start();
        } else {
            timer.stop();
        }
    }

    public void updatePlayTime() {
        currentPlayTime -= 1000;
        setChanged();
        notifyObservers();
    }

    public void resetPlayTime() {
        currentPlayTime = 0;
        setChanged();
        notifyObservers();
    }
}
